package com.tools.middle.redis.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.tools.common.container.MapEntry;
import com.tools.common.container.MapEnum;
import com.tools.common.container.OwnPairs;
import com.tools.common.container.OwnRows;
import com.tools.common.object.C;
import com.tools.common.object.json.JsonKit;
import com.tools.common.object.Note;
import com.tools.common.object.ObjKit;
import com.tools.common.thread.Timeunit;
import redis.clients.jedis.ZParams;

import java.util.*;

/**
 * Redis 数据结构与 Java 类之间转换操作的工具类
 * */
@Note("Redis 数据结构与 Java 类之间转换操作的工具类")
final class DataTypeKit {


    @Note("判断返回的时间等等 long 值是否为 null，若为 null 替换为 -1")
    static long default_returnTimeResult(Long result) {
        return (result == null) ? -1 : result;
    }

    @Note("判断返回的结果条目等等 long 值是否为 null，若为 null 替换为 0")
    static long default_returnResultLong(Long result) {
        return (result == null) ? 0 : result;
    }

    @Note("校验过期时间单位")
    static void default_checkTimeunit(Timeunit timeunit) {
        if(timeunit == null) throw new NullPointerException("过期时间单位为 null");
    }

    @Note("校验 key 或哈希类型的 field 是否为空值")
    static void default_checkKey(String key) {
        if(key == null || key.isEmpty()) throw new NullPointerException("不允许处理空的 key 或 field");
    }

    @Note("校验多个 key 或多个哈希类型的 field 是否藏有空值")
    static void default_checkKeys(String[] keys) {
        if(keys == null || keys.length == 0) throw new NullPointerException("至少需要一个或多个 key 或 field");
        for (int i = 0; i < keys.length; i++) {
            if(keys[i] == null || keys[i].isEmpty()) {
                throw new NullPointerException("第 "+ i +" 个 key 或 field 为空");
            }
        }
    }


    @Note("将字符串类型可迭代容器转为字符串数组返回")
    static String[] default_asStringKeyArray(Iterable<String> keys) {
        if(keys == null) throw new NullPointerException("至少需要一个或多个 key 或 field");
        String[] keyArray;
        int length;
        if(keys instanceof Collection) {
            Collection<String> c = (Collection<String>) keys;
            if(c.isEmpty()) throw new NullPointerException("至少需要一个或多个 key 或 field");
            int size = c.size();
            keyArray = new String[size];
            length = size;
        } else if(keys instanceof OwnRows) {
            OwnRows<String> r = (OwnRows<String>) keys;
            if(r.isEmpty()) throw new NullPointerException("至少需要一个或多个 key 或 field");
            int size = r.size();
            length = size;
            keyArray = new String[size];
        } else {
            Iterator<String> iterator = keys.iterator();
            if(!iterator.hasNext()) throw new NullPointerException("至少需要一个或多个 key 或 field");
            int size = 0;
            while (iterator.hasNext()) {
                String key = iterator.next();
                if(key == null || key.isEmpty()) throw new NullPointerException("第 " + size + " 个 key 或 field 为空");
                size++;
            }
            keyArray = new String[size];
            length = size;
        }
        int index = 0;
        for (String key : keys) {
            if(index == length) return keyArray;
            default_checkKey(key);
            keyArray[index] = key;
            index++;
        }
        return keyArray;
    }


    @Note("将对象类型数组转为字符串数组返回")
    static String[] default_asStringArray(Object[] values) {
        if(values == null) throw new NullPointerException("至少需要一个或多个 value");
        int length = values.length;
        if(length == 0) throw new NullPointerException("至少需要一个或多个 value");
        String[] strValues = new String[length];
        for (int i = 0; i < length; i++) {
            strValues[i] = ObjKit.toStringEmptyString(values[i]);
        }
        return strValues;
    }


    @Note("将对象类型数组转为字符串数组返回")
    static String[] default_asStringArray(Iterable values) {
        if(values == null) throw new NullPointerException("至少需要一个或多个 value");
        String[] valueArray;
        int length;
        if(values instanceof Collection) {
            Collection c = (Collection) values;
            if(c.isEmpty()) throw new NullPointerException("至少需要一个或多个 key 或 field");
            int size = c.size();
            valueArray = new String[size];
            length = size;
        } else if(values instanceof OwnRows) {
            OwnRows r = (OwnRows) values;
            if(r.isEmpty()) throw new NullPointerException("至少需要一个或多个 key 或 field");
            int size = r.size();
            length = size;
            valueArray = new String[size];
        } else {
            Iterator iterator = values.iterator();
            if(!iterator.hasNext()) throw new NullPointerException("至少需要一个或多个 value");
            int size = 0;
            while (iterator.hasNext()) {
                iterator.next();
                size++;
            }
            valueArray = new String[size];
            length = size;
        }
        int index = 0;
        for (Object value : values) {
            if(index == length) return valueArray;
            valueArray[index] = ObjKit.toStringEmptyString(value);
            index++;
        }
        return valueArray;
    }

    @Note("处理字符串列表结果，将其转为对象类型的列表返回")
    static List<Object> default_asObjectList(List<String> result) {
        List<Object> finalResult = new ArrayList<>(result.size());
        for (String s : result) {
            Object value = ObjKit.stringToRealValue(s, true);
            finalResult.add(value);
        }
        return finalResult;
    }


    @Note("将字符串列表转为指定类型的列表")
    static <T> List<T> default_asSpecifyTypeList(List<String> res, C<T> c) {
        List<T> result = new ArrayList<>(res.size());
        for (String s : res) {
            result.add((T) ObjKit.stringToRealValue(s, c));
        }
        return result;
    }


    @Note("将字符串列表转为指定类型的列表")
    static <T> List<T> default_asSpecifyTypeList(List<String> res, TypeReference<T> type) {
        List<T> result = new ArrayList<>(res.size());
        for (String s : res) {
            result.add(JsonKit.toEntity(s, type));
        }
        return result;
    }


    @Note("将字符串列表转为指定类型的列表")
    static <T> List<T> default_asSpecifyTypeList(List<String> res, Class<T> type) {
        List<T> result = new ArrayList<>(res.size());
        for (String s : res) {
            result.add(JsonKit.toEntity(s, type));
        }
        return result;
    }


    @Note("校验或替换 key 为字符串类型")
    static String default_toStringKey(Object key) {
        return (key == null) ? "null" : key.toString();
    }


    @Note("转换任意泛型的 Map 集合为字符串类型的 key-value Map 集合，方便 hash 类型处理")
    static Map<String, String> default_asStringValueMap(Map map) {
        if(map == null || map.isEmpty()) throw new NullPointerException("存储 hash 类型至少需要一个或多个 field-value");
        Map<String, String> result = new HashMap<>(MapEnum.calcInitSize(map.size()));
        for (Object o : map.entrySet()) {
            Map.Entry e = (Map.Entry) o;
            result.put(default_toStringKey(e.getKey()), ObjKit.toStringEmptyString(e.getValue()));
        }
        return result;
    }


    @Note("转换任意泛型的自定义键值对容器集合为字符串类型的 key-value Map 集合，方便 hash 类型处理")
    static Map<String, String> default_asStringValueMap(OwnPairs pairs) {
        if(pairs != null && !pairs.isEmpty()) {
            Map<String, String> result = new HashMap<>((int) (pairs.size() / 0.75) + 1);
            for (Object o : pairs.entrySet()) {
                Map.Entry e = (Map.Entry) o;
                result.put(default_toStringKey(e.getKey()), ObjKit.toStringEmptyString(e.getValue()));
            }
            return result;
        }
        throw new NullPointerException("存储 hash 类型至少需要一个或多个 field-value");
    }

    @Note("将返回的 key-value 都是字符串类型的 Map 集合转为标准 Map 集合（key 为字符串 value 为 Object）")
    static Map<String, Object> default_asStandardMap(Map<String, String> res) {
        Map<String, Object> result = new HashMap<>(MapEnum.calcInitSize(res.size()));
        for (Map.Entry<String, String> e : res.entrySet()) {
            result.put(e.getKey(), ObjKit.stringToRealValue(e.getValue(), true));
        }
        return result;
    }


    @Note("hmget 获取的数据组合成标准类型的 key-value 的 Map 集合")
    static Map<String, Object> default_hashResultAsMap(String[] fields, List<String> res) {
        int length = fields.length;
        Map<String, Object> result = new HashMap<>(MapEnum.calcInitSize(length));
        for (int i = 0; i < length; i++) {
            String s = res.get(i);
            result.put(fields[i], ObjKit.stringToRealValue(s, true));
        }
        return result;
    }


    @Note("将字符串的 Set 集合转为 Object 类型的 Set 集合输出")
    static Set<Object> default_asObjectSet(Set<String> res) {
        Set<Object> results = new HashSet<>(MapEnum.calcInitSize(res.size()));
        for (String s : res) {
            results.add(ObjKit.stringToRealValue(s, true));
        }
        return results;
    }

    @Note("将字符串 Set 集合转为指定类型的 Set 集合")
    static <T>Set<T> default_asSpecifyTypeSet(Set<String> res, Class<T> c) {
        Set<T> results = new HashSet<>(MapEnum.calcInitSize(res.size()));
        for (String s : res) {
            results.add(JsonKit.toEntity(s, c));
        }
        return results;
    }

    @Note("将字符串 Set 集合转为指定类型的 Set 集合")
    static <T>Set<T> default_asSpecifyTypeSet(Set<String> res, TypeReference<T> typeReference) {
        Set<T> results = new HashSet<>(MapEnum.calcInitSize(res.size()));
        for (String s : res) {
            results.add(JsonKit.toEntity(s, typeReference));
        }
        return results;
    }

    @Note("将字符串 Set 集合转为指定类型的 Set 集合")
    static <T>Set<T> default_asSpecifyTypeSet(Set<String> res, C<T> c) {
        Set<T> results = new HashSet<>(MapEnum.calcInitSize(res.size()));
        for (String s : res) {
            results.add((T) ObjKit.stringToRealValue(s, c));
        }
        return results;
    }


    @Note("判断返回的分值 double 值是否为 null，若为 null 替换为 0.0")
    static double default_returnDoubleScore(Double score) {
        return (score == null) ? 0.0 : score;
    }

    @Note("将 Object 类型的 key 的 Map 集合转为 String 类型的 key 的 Map")
    static Map<String, Double> default_asStringKeyMap(Map<Object, Double> map) {
        if(map == null || map.isEmpty()) throw new NullPointerException("至少需要一个或多个 value-score");
        Map<String, Double> result = new HashMap<>(MapEnum.calcInitSize(map.size()));
        for (Map.Entry<Object, Double> e : map.entrySet()) {
            result.put(ObjKit.toStringEmptyString(e.getKey()), e.getValue());
        }
        return result;
    }

    @Note("将 Object 类型的 key 的自定义键值对容器转为 String 类型的 key 的 Map")
    static Map<String, Double> default_asStringKeyMap(OwnPairs<Object, Double> pairs) {
        if(pairs != null && !pairs.isEmpty()) {
            Map<String, Double> result = new HashMap<>((int) (pairs.size() / 0.75) + 1);
            for (Map.Entry<Object, Double> e : pairs.entrySet()) {
                result.put(ObjKit.toStringEmptyString(e.getKey()), e.getValue());
            }
            return result;
        }
        throw new NullPointerException("至少需要一个或多个 value-score");
    }

    @Note("检查 ZParams 是否为 null")
    static void default_checkZParamsIsNotNull(ZParams params) {
        if(params == null) throw new NullPointerException("ZParams 不能为 null");
    }


    @Note("将 List<Map.Entry<String, String>> 的 value 转为 Object 类型")
    static List<Map.Entry<String, Object>> default_asObjectTypeList(List<Map.Entry<String, String>> src) {
        if(src == null || src.isEmpty()) return new ArrayList<>();
        List<Map.Entry<String, Object>> result = new ArrayList<>(src.size());
        for (Map.Entry<String, String> e : src) {
            result.add(new MapEntry<>(e.getKey(), ObjKit.stringToRealValue(e.getValue(), true)));
        }
        return result;
    }

    @Note("将 List<Map.Entry<String, String>> 的转为 Map<String, Object>")
    static Map<String, Object> default_asObjectValueTypeMap(List<Map.Entry<String, String>> src) {
        if(src == null || src.isEmpty()) return new HashMap<>();
        Map<String, Object> result = new HashMap<>(MapEnum.calcInitSize(src.size()));
        for (Map.Entry<String, String> e : src) {
            result.put(e.getKey(), ObjKit.stringToRealValue(e.getValue(), true));
        }
        return result;
    }


    @Note("将 map 转为 [key1, value1, key2, value2……] 的字符串数组")
    static String[] default_asKeyValueStringArray(Map<String, Object> keyAndValue) {
        if(keyAndValue == null || keyAndValue.isEmpty()) {
            throw new IllegalArgumentException("至少需要一个 key-value");
        }
        String[] param = new String[keyAndValue.size() * 2];
        int keyIndex = 0;
        int valueIndex = 1;
        for(Map.Entry<String, Object> e : keyAndValue.entrySet()) {
            String key = e.getKey();
            DataTypeKit.default_checkKey(key);
            String value = ObjKit.toStringNullString(e.getValue());
            param[keyIndex] = key;
            param[valueIndex] = value;
            keyIndex++;
            valueIndex++;
        }
        return param;
    }


    @Note("将 map 转为 [key1, value1, key2, value2……] 的字符串数组")
    static String[] default_asKeyValueStringArray(OwnPairs<String, Object> keyAndValue)  {
        if(keyAndValue == null || keyAndValue.isEmpty()) {
            throw new IllegalArgumentException("至少需要一个 key-value");
        }
        int valueIndex = 1;
        int keyIndex = 0;
        String[] param = new String[keyAndValue.size() * 2];
        for(Map.Entry<String, Object> e : keyAndValue.entrySet()) {
            String key = e.getKey();
            DataTypeKit.default_checkKey(key);
            param[valueIndex] = ObjKit.toStringNullString(e.getValue());
            param[keyIndex] = key;
            valueIndex++;
            keyIndex++;
        }
        return param;
    }

    @Note("要执行的 lua 脚本不能为空")
    static void default_checkLuaScriptIsNotEmpty(String luaScript) {
        if(luaScript == null || luaScript.isEmpty()) throw new IllegalArgumentException("lua 脚本为空");
    }

    @Note("将 src 的值转为字符串后放入 result 里")
    static void default_copyToStringCollection(Collection<String> result, Object src) {
        if(src instanceof Iterable) {
            for(Object e : (Iterable) src) {
                result.add(ObjKit.toStringNullString(e));
            }
            return;
        }
        for(Object e : (Object[]) src) {
            result.add(ObjKit.toStringNullString(e));
        }
    }
}



